package org.gdstash.ui.character;

import org.gdstash.character.GDChar;
import org.gdstash.character.GDCharSkill;
import org.gdstash.db.*;
import org.gdstash.file.DDSLoader;
import org.gdstash.ui.GDStashFrame;
import org.gdstash.ui.util.AdjustablePanel;
import org.gdstash.util.GDImagePool;

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.LinkedList;
import java.util.List;

public class GDCharMasteryImagePane extends AdjustablePanel {
    private static final String STR_BACKGROUND = "records/ui/skills/class01/classpanelbackgroundimage.dbr";
    private static final String STR_SQUARE_GOLD = "records/ui/skills/classcommon/skillbuttons_goldbitmap.dbr";
    private static final String STR_ROUND_GOLD = "records/ui/skills/classcommon/skillbuttons_goldroundbitmap.dbr";
    private static int[] LEVEL_TIER;
    private static int[] LEVEL_BAR;
    private static BufferedImage IMG_BACKGROUND;
    private static BufferedImage BORDER_SQUARE_GOLD;
    private static BufferedImage BORDER_ROUND_GOLD;
    private static Font SKILL_FONT;
    private GDChar gdc;
    private DBClassTable classTable;
    private DBSkillTree skillTree;
    private Skill mastery;
    private List<Skill> skills;
    private JPanel pnlMastery;
    private BufferedImage bgImage;
    private GDUIMasterySupport masterySupport;
    private boolean selMastery;
    private int pointsSpent;

    public static void initStats() {
        DBBitmap bmp = null;
        bmp = DBBitmap.get("records/ui/skills/class01/classpanelbackgroundimage.dbr");
        if (bmp != null) {
            GDCharMasteryImagePane.IMG_BACKGROUND = bmp.getImage();
        }
        bmp = DBBitmap.get("records/ui/skills/classcommon/skillbuttons_goldbitmap.dbr");
        if (bmp != null) {
            GDCharMasteryImagePane.BORDER_SQUARE_GOLD = bmp.getImage();
        }
        bmp = DBBitmap.get("records/ui/skills/classcommon/skillbuttons_goldroundbitmap.dbr");
        if (bmp != null) {
            GDCharMasteryImagePane.BORDER_ROUND_GOLD = bmp.getImage();
        }
        final DBEngineGame game = DBEngineGame.get();
        if (game == null) {
            return;
        }
        final int levels = game.getMaxMasteryLevel();
        final int numTiers = game.getNumSkillTiers();
        final DBEngineMasteryTier[] tiers = game.getSkillTierArray();
        if (tiers == null) {
            return;
        }
        GDCharMasteryImagePane.LEVEL_TIER = new int[levels + 1];
        GDCharMasteryImagePane.LEVEL_BAR = new int[levels + 1];
        GDCharMasteryImagePane.LEVEL_TIER[0] = 0;
        for (int i = 0; i < tiers.length - 1; ++i) {
            for (int j = tiers[i].getMasteryLevel(); j < tiers[i + 1].getMasteryLevel(); ++j) {
                GDCharMasteryImagePane.LEVEL_TIER[j] = tiers[i].getMasteryTier();
            }
            for (int j = tiers[i + 1].getMasteryLevel(); j < GDCharMasteryImagePane.LEVEL_TIER.length; ++j) {
                GDCharMasteryImagePane.LEVEL_TIER[j] = tiers[i + 1].getMasteryTier();
            }
        }
        GDCharMasteryImagePane.LEVEL_BAR[0] = 0;
        int lastLevel = 0;
        float total = 0.0f;
        for (int k = 0; k < tiers.length; ++k) {
            final float step = 720.0f / numTiers / (tiers[k].getMasteryLevel() - lastLevel);
            for (int l = lastLevel + 1; l <= tiers[k].getMasteryLevel(); ++l) {
                total += step;
                GDCharMasteryImagePane.LEVEL_BAR[l] = Math.round(total);
            }
            lastLevel = tiers[k].getMasteryLevel();
        }
    }

    static {
        GDCharMasteryImagePane.LEVEL_TIER = new int[]{0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9};
        GDCharMasteryImagePane.LEVEL_BAR = new int[]{0, 80, 100, 120, 140, 160, 176, 192, 208, 224, 240, 256, 272, 288, 304, 320, 336, 352, 368, 384, 400, 416, 432, 448, 464, 480, 491, 503, 514, 526, 537, 549, 560, 570, 580, 590, 600, 610, 620, 630, 640, 648, 656, 664, 672, 680, 688, 696, 704, 712, 720};
        GDCharMasteryImagePane.SKILL_FONT = new Font("Serif", 1, 16);
    }

    @Override
    public void adjustUI() {
        this.createImage();
        this.repaint();
    }

    public void updateConfig() {
    }

    private Skill getSkill(final int x, final int y) {
        final int cX = this.getX();
        final int cY = this.getY();
        Skill sk = null;
        for (final Skill mps : this.skills) {
            final int imgX = mps.button.getPosX();
            final int imgY = mps.button.getPosY();
            final int imgH = mps.skill.getImageUp().getHeight() + 2 * mps.button.getOffsetX();
            final int imgW = mps.skill.getImageUp().getWidth() + 2 * mps.button.getOffsetY();
            if (imgX <= x && imgX + imgW >= x && imgY <= y && imgY + imgH >= y) {
                sk = mps;
                break;
            }
        }
        return sk;
    }

    public String getSkillDescription(final int x, final int y) {
        int xPos = x;
        int yPos = y;
        if (GDStashFrame.iniConfig.sectUI.graphicScale != 100) {
            xPos = xPos * 100 / GDStashFrame.iniConfig.sectUI.graphicScale;
            yPos = yPos * 100 / GDStashFrame.iniConfig.sectUI.graphicScale;
        }
        final Skill mps = this.getSkill(xPos, yPos);
        String s = null;
        if (mps != null) {
            s = mps.skill.getSkillNextLevelDescription(mps.skillLevel, this.masterySupport.getCharLevel());
        }
        return s;
    }

    public String decSkill(final int x, final int y) {
        int xPos = x;
        int yPos = y;
        if (GDStashFrame.iniConfig.sectUI.graphicScale != 100) {
            xPos = xPos * 100 / GDStashFrame.iniConfig.sectUI.graphicScale;
            yPos = yPos * 100 / GDStashFrame.iniConfig.sectUI.graphicScale;
        }
        final Skill mps = this.getSkill(xPos, yPos);
        String s = null;
        if (mps != null) {
            boolean dec = true;
            if (mps.mastery) {
                int maxTier = 0;
                for (final Skill sk : this.skills) {
                    if (sk.skillLevel > 0) {
                        final int tier = sk.skill.getSkillTier();
                        if (maxTier >= tier) {
                            continue;
                        }
                        maxTier = tier;
                    }
                }
                if (mps.skillLevel <= 0) {
                    dec = false;
                } else {
                    int idx = mps.skillLevel - 1;
                    if (idx > GDCharMasteryImagePane.LEVEL_TIER.length - 1) {
                        idx = GDCharMasteryImagePane.LEVEL_TIER.length - 1;
                    }
                    if (maxTier > GDCharMasteryImagePane.LEVEL_TIER[idx]) {
                        dec = false;
                    }
                }
            } else {
                if (mps.skillLevel <= 0) {
                    dec = false;
                }
                if (mps.skill.isBaseSkill() && mps.skillLevel == 1) {
                    boolean check = false;
                    for (final Skill sk : this.skills) {
                        if (sk.skill.isBaseSkill()) {
                            if (check) {
                                break;
                            }
                            if (!mps.button.getButtonID().equals(sk.button.getButtonID())) {
                                continue;
                            }
                            check = true;
                        } else {
                            if (check && sk.skillLevel > 0) {
                                dec = false;
                                break;
                            }
                            continue;
                        }
                    }
                }
            }
            if (dec) {
                --mps.skillLevel;
                --this.pointsSpent;
                this.masterySupport.setSkillPoints(this.masterySupport.getSkillPoints() + 1);
                this.createImage();
                this.repaint();
            }
            s = mps.skill.getSkillNextLevelDescription(mps.skillLevel, this.masterySupport.getCharLevel());
        }
        return s;
    }

    public String incSkill(final int x, final int y) {
        int xPos = x;
        int yPos = y;
        if (GDStashFrame.iniConfig.sectUI.graphicScale != 100) {
            xPos = xPos * 100 / GDStashFrame.iniConfig.sectUI.graphicScale;
            yPos = yPos * 100 / GDStashFrame.iniConfig.sectUI.graphicScale;
        }
        final Skill mps = this.getSkill(xPos, yPos);
        String s = null;
        if (mps != null) {
            boolean inc = true;
            if (mps.mastery) {
                if (mps.skillLevel >= mps.skill.getMaxLevel()) {
                    inc = false;
                }
            } else {
                if (mps.skillLevel >= mps.skill.getMaxLevel()) {
                    inc = false;
                }
                int idx = this.mastery.skillLevel;
                if (idx > GDCharMasteryImagePane.LEVEL_TIER.length - 1) {
                    idx = GDCharMasteryImagePane.LEVEL_TIER.length - 1;
                }
                if (mps.skill.getSkillTier() > GDCharMasteryImagePane.LEVEL_TIER[idx]) {
                    inc = false;
                }
                if (mps.skill.getSkillDependencyList() != null && !mps.skill.getSkillDependencyList().isEmpty()) {
                    int count = 0;
                    for (final DBSkillDependency dep : mps.skill.getSkillDependencyList()) {
                        if (this.masterySupport.getPointsForSkill(dep.getDependentSkillID()) > 0) {
                            ++count;
                        }
                    }
                    if (mps.skill.isDependencyAll()) {
                        if (count < mps.skill.getSkillDependencyList().size()) {
                            inc = false;
                        }
                    } else if (count == 0) {
                        inc = false;
                    }
                }
                if (!mps.skill.isBaseSkill() && mps.base.skillLevel <= 0) {
                    inc = false;
                }
            }
            final int points = this.masterySupport.getSkillPoints();
            if (points <= 0) {
                inc = false;
            }
            if (inc) {
                ++mps.skillLevel;
                ++this.pointsSpent;
                this.masterySupport.setSkillPoints(points - 1);
                this.createImage();
                this.repaint();
            }
            s = mps.skill.getSkillNextLevelDescription(mps.skillLevel, this.masterySupport.getCharLevel());
        }
        return s;
    }

    public int getPointsSpent() {
        return this.pointsSpent;
    }

    public int getPointsForSkill(final String skillID) {
        int points = 0;
        for (final Skill sk : this.skills) {
            if (sk.skill.getSkillID().equals(skillID)) {
                points = sk.skillLevel;
                break;
            }
        }
        return points;
    }

    public void setChar(final GDChar gdc) {
        this.gdc = gdc;
    }

    public void updateChar(final GDChar gdc) {
        if (gdc == null) {
            return;
        }
        if (this.mastery == null) {
            return;
        }
        gdc.setMasterySkills(this.mastery.skill.getSkillID(), this.skills);
    }

    private void determineMasterySkills(final String masteryID) {
        this.classTable = null;
        this.skillTree = null;
        this.mastery = null;
        this.skills.clear();
        this.pointsSpent = 0;
        if (masteryID == null) {
            return;
        }
        if (!this.selMastery) {
            boolean found = false;
            if (this.gdc != null) {
                final GDChar.SkillInfo[] infos = this.gdc.getMasteryInfo();
                if (infos != null) {
                    for (int i = 0; i < infos.length; ++i) {
                        if (infos[i].id.equals(masteryID)) {
                            found = true;
                            break;
                        }
                    }
                }
            }
            if (!found) {
                return;
            }
        }
        final DBSkillButton sb = DBSkillButton.getBySkillID(masteryID);
        if (sb == null) {
            return;
        }
        this.classTable = DBClassTable.getByMasteryID(sb.getButtonID());
        if (this.classTable == null) {
            return;
        }
        final List<DBClassTableButton> buttons = this.classTable.getButtonList();
        if (masteryID != null) {
            final String treeID = DBSkillTreeAlloc.getTreeIDBySkillID(masteryID);
            if (treeID != null) {
                this.skillTree = DBSkillTree.get(treeID);
            }
        }
        int index = 1;
        for (final String skillID : this.skillTree.getSkillIDList()) {
            for (final DBClassTableButton button : buttons) {
                if (button.getSkill() == null) {
                    continue;
                }
                if (skillID.equals(button.getSkill().getSkillID())) {
                    final Skill temp = new Skill();
                    temp.button = button.getButton();
                    temp.skill = button.getSkill();
                    temp.base = null;
                    temp.index = index;
                    temp.skillLevel = 0;
                    temp.mastery = false;
                    if (temp.skill.isMastery()) {
                        temp.mastery = true;
                        this.mastery = temp;
                    }
                    if (!this.selMastery) {
                        final List<GDCharSkill> charSkills = this.gdc.getSkillsByMastery(masteryID);
                        for (final GDCharSkill cs : charSkills) {
                            if (cs.getID().equals(temp.skill.getSkillID())) {
                                temp.skillLevel = cs.getLevel();
                                this.pointsSpent += temp.skillLevel;
                                break;
                            }
                        }
                    }
                    this.skills.add(temp);
                    break;
                }
            }
            ++index;
        }
        Skill base = null;
        for (final Skill mps : this.skills) {
            if (mps.skill.isBaseSkill()) {
                base = mps;
            } else {
                mps.base = base;
            }
        }
    }

    public GDCharMasteryImagePane(final GDUIMasterySupport masterySupport, final boolean selMastery) {
        this.masterySupport = masterySupport;
        this.selMastery = selMastery;
        this.skills = new LinkedList<Skill>();
        this.bgImage = GDCharMasteryImagePane.IMG_BACKGROUND;
    }

    public void setMastery(final String masteryID) {
        this.determineMasterySkills(masteryID);
        this.createImage();
        this.repaint();
    }

    public void paintComponent(final Graphics g) {
        super.paintComponent(g);
        if (this.bgImage == null) {
            return;
        }
        g.drawImage(this.drawGraphics(), 0, 0, null);
    }

    @Override
    public Dimension getPreferredSize() {
        if (this.bgImage == null) {
            return super.getPreferredSize();
        }
        final int w = this.bgImage.getWidth();
        final int h = this.bgImage.getHeight();
        return new Dimension(w, h);
    }

    @Override
    public Dimension getMaximumSize() {
        return this.getPreferredSize();
    }

    @Override
    public Dimension getMinimumSize() {
        return this.getPreferredSize();
    }

    public int getPreferredWidth() {
        return (int) this.getPreferredSize().getWidth();
    }

    public int getPreferredHeight() {
        return (int) this.getPreferredSize().getHeight();
    }

    private BufferedImage drawGraphics() {
        if (this.bgImage == null) {
            return null;
        }
        Graphics g = null;
        BufferedImage image = null;
        image = new BufferedImage(this.bgImage.getWidth(), this.bgImage.getHeight(), this.bgImage.getType());
        g = image.createGraphics();
        g.drawImage(this.bgImage, 0, 0, null);
        return image;
    }

    private void createImage() {
        BufferedImage image = null;
        if (this.classTable != null) {
            final DBBitmap bar = this.classTable.getMasteryBarDB();
            final DBBitmap img = this.classTable.getMasteryBitmapDB();
            final DBBitmap bg = this.classTable.getSkillPaneDB();
            BufferedImage bi = null;
            if (bg == null) {
                bi = GDCharMasteryImagePane.IMG_BACKGROUND;
            } else {
                bi = bg.getImage();
            }
            Graphics g = null;
            image = new BufferedImage(bi.getWidth(), bi.getHeight(), bi.getType());
            g = image.createGraphics();
            g.drawImage(bi, 0, 0, null);
            if (img != null) {
                g.drawImage(img.getImage(), img.getPosX(), img.getPosY(), null);
            }
            if (this.mastery != null) {
                g.drawImage(bar.getImage(), bar.getPosX(), bar.getPosY(), GDCharMasteryImagePane.LEVEL_BAR[this.mastery.skillLevel], bar.getImage().getHeight(), null);
            }
            final List<DBClassTableButton> btns = this.classTable.getButtonList();
            for (final Skill mps : this.skills) {
                final List<DBSkillConnector> connections = mps.skill.getSkillConnectionList();
                final int imgX = mps.button.getPosX() + mps.button.getOffsetX();
                final int imgY = mps.button.getPosY() + mps.button.getOffsetY();
                if (connections != null && !connections.isEmpty()) {
                    int x = imgX + 32;
                    final int y = imgY - 24;
                    for (final DBSkillConnector connection : connections) {
                        if (connection == null) {
                            continue;
                        }
                        final BufferedImage coff = connection.getConnectionOff();
                        final BufferedImage con = connection.getConnectionOn();
                        if (con == null || coff == null) {
                            continue;
                        }
                        if (mps.skillLevel == 0) {
                            g.drawImage(connection.getConnectionOff(), x, y, null);
                        } else {
                            g.drawImage(connection.getConnectionOn(), x, y, null);
                        }
                        BufferedImage ci = connection.getConnectionOn();
                        if (ci == null) {
                            ci = connection.getConnectionOff();
                        }
                        x += ci.getWidth();
                    }
                }
            }
            for (final Skill mps : this.skills) {
                final int imgX2 = mps.button.getPosX() + mps.button.getOffsetX();
                final int imgY2 = mps.button.getPosY() + mps.button.getOffsetY();
                final int brdX = mps.button.getPosX();
                final int brdY = mps.button.getPosY();
                if (mps.mastery) {
                    g.drawImage(mps.skill.getImageUp(), imgX2, imgY2, null);
                } else {
                    int idx = this.mastery.skillLevel;
                    if (idx > GDCharMasteryImagePane.LEVEL_TIER.length - 1) {
                        idx = GDCharMasteryImagePane.LEVEL_TIER.length - 1;
                    }
                    if (mps.skill.getSkillTier() <= GDCharMasteryImagePane.LEVEL_TIER[idx]) {
                        if (mps.skill.isBaseSkill()) {
                            if (mps.button.isCircularButton()) {
                                g.drawImage(GDCharMasteryImagePane.BORDER_ROUND_GOLD, brdX, brdY, null);
                            } else {
                                g.drawImage(GDCharMasteryImagePane.BORDER_SQUARE_GOLD, brdX, brdY, null);
                            }
                        } else if (mps.base.skillLevel > 0) {
                            if (mps.button.isCircularButton()) {
                                g.drawImage(GDCharMasteryImagePane.BORDER_ROUND_GOLD, brdX, brdY, null);
                            } else {
                                g.drawImage(GDCharMasteryImagePane.BORDER_SQUARE_GOLD, brdX, brdY, null);
                            }
                        } else if (mps.button.isCircularButton()) {
                            g.drawImage(GDImagePool.imgBorderRound, brdX, brdY, null);
                        } else {
                            g.drawImage(GDImagePool.imgBorderSquare, brdX, brdY, null);
                        }
                    } else if (mps.button.isCircularButton()) {
                        g.drawImage(GDImagePool.imgBorderRound, brdX, brdY, null);
                    } else {
                        g.drawImage(GDImagePool.imgBorderSquare, brdX, brdY, null);
                    }
                    if (mps.skillLevel == 0) {
                        BufferedImage si = mps.skill.getImageDown();
                        if (si == null) {
                            si = mps.skill.getImageUp();
                        }
                        g.drawImage(si, imgX2, imgY2, null);
                    } else {
                        g.drawImage(mps.skill.getImageUp(), imgX2, imgY2, null);
                        g.setColor(Color.CYAN);
                        g.setFont(GDCharMasteryImagePane.SKILL_FONT);
                        if (mps.skillLevel < 10) {
                            g.drawString(Integer.toString(mps.skillLevel) + " / " + Integer.toString(mps.skill.getMaxLevel()), imgX2 - 2, imgY2 + 52);
                        } else {
                            g.drawString(Integer.toString(mps.skillLevel) + " / " + Integer.toString(mps.skill.getMaxLevel()), imgX2 - 6, imgY2 + 52);
                        }
                    }
                }
            }
        }
        if (image == null) {
            this.bgImage = GDCharMasteryImagePane.IMG_BACKGROUND;
        } else {
            this.bgImage = image;
        }
        if (this.bgImage != null && GDStashFrame.iniConfig.sectUI.graphicScale != 100) {
            final int w = this.bgImage.getWidth() * GDStashFrame.iniConfig.sectUI.graphicScale / 100;
            final int h = this.bgImage.getHeight() * GDStashFrame.iniConfig.sectUI.graphicScale / 100;
            this.bgImage = DDSLoader.getScaledImage(this.bgImage, w, h);
        }
    }

    public static class Skill {
        public DBSkillButton button;
        public DBSkill skill;
        public Skill base;
        public int index;
        public int skillLevel;
        public boolean mastery;
    }
}
